package com.zp.demo.repush.config;

import com.zp.demo.repush.RePushUtils;
import com.zp.demo.repush.anno.RePushAnno;
import com.zp.demo.repush.anno.RePushCutAnno;
import com.zp.demo.repush.service.defined.DefinedRePushInter;
import com.zp.demo.repush.vo.RePushProperties;
import com.zp.demo.repush.vo.RePushStrategyEntity;
import lombok.extern.log4j.Log4j2;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 说明：重推 服务bean定义
 * @author 张鹏
 * @create
 */
@Component
@Log4j2
public class BaseRePushConfig {
    List<String> classNames = new ArrayList<>();
    @Bean
    public ConcurrentMap<String,String> lockMap(){
        ConcurrentMap<String,String> lockMap = new ConcurrentHashMap<>();
        return lockMap;
    }
    /**
     * 所有的 自定义 异常处理，如果有定义将优先执行自定义处理类
     * @Author 张鹏
     * @Date 2018/12/29 17:41
     * @param pushDataInters
     * @return
     */
    @Bean
    public Map<String,DefinedRePushInter> defindRePushServiceMap(List<DefinedRePushInter> pushDataInters){
        Map<String,DefinedRePushInter> rePushServiceMap = new HashMap<>();
        pushDataInters.forEach(x ->{
            rePushServiceMap.put(x.methodId(),x);
        });
        return rePushServiceMap;
    }

    /**
     *  策略配置信息 各个异常处理的 重推频率，次数等信息
     * @param rePushProperties
     * @return
     */
    @Bean
    public Map<String,RePushStrategyEntity> exceptionStrategy(RePushProperties rePushProperties){
        return rePushProperties.getStrategy();
    }
    /**
     * 重推的 方法id及其 方法映射
     * @return
     */
    @Bean
    public Map<String,Method> rePushHandleMap(RePushProperties rePushProperties){
        // 扫描  出所有的包
        doScan(rePushProperties.getScanBasePack());
        return methodIdMapping(classNames);
    }
    @Bean
    public ThreadPoolTaskExecutor poolTaskExecutor(){
        ThreadPoolTaskExecutor poolTaskExecutor = new ThreadPoolTaskExecutor();
        poolTaskExecutor.setMaxPoolSize(10);
        poolTaskExecutor.setCorePoolSize(5);
        poolTaskExecutor.setQueueCapacity(30);
        poolTaskExecutor.setKeepAliveSeconds(300);
        poolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return poolTaskExecutor;

    }
    public Map<String,Method> methodIdMapping(List<String> classNames) {
        Map<String,Method> handerMap = new HashMap<>();
        classNames.forEach(string ->{
            if(string != null) {

                String clazzName = "";
                String cn = string.replace(".class", "");
                try {
                    Class<?> clazz = Class.forName(cn);
                    // 获取注解
                    if (clazz.isAnnotationPresent(RePushAnno.class)) {
                        RePushAnno rePushAnno = clazz.getAnnotation(RePushAnno.class);
                        if (rePushAnno.value() != null && !"".equals(rePushAnno.value())) {
                            clazzName = rePushAnno.value();
                        }else{
                            clazzName = clazz.getName();
                        }
                    }else{
                        clazzName = clazz.getName();
                    }
                    // 关键是有没有方法
                    Method[] methods = clazz.getMethods();
                    for (Method method : methods) {
                        String methodId = "";
                        if (method.isAnnotationPresent(RePushAnno.class) || method.isAnnotationPresent(RePushCutAnno.class)) {
                            methodId = RePushUtils.getMMId(clazz,clazzName,method);
//                            Field field_name = Method.class.getDeclaredField("name");
//                            field_name.setAccessible(true);
//                            field_name.set(method, "[copy]"+method.getName());
                            handerMap.put(methodId, method);
                            log.info("[RePush]methodIdMapping:" + methodId);
                        } else {
                            continue;
                        }
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        });
        return handerMap;
    }

    // 扫描
    public List<String> doScan(String basePackage) {
        URL url = this.getClass().getClassLoader().getResource(basePackage.replaceAll("\\.", "/"));
        // url报空指针呢
        String fileStr = url.getFile();
        File file = new File(url.getFile());
        return getFileClass(file, basePackage);
    }

    /**
     * 遍历获取所有该包下面的所有 class
     * @param file
     * @param basePackage
     */
    private List<String> getFileClass(File file, String basePackage) {
        File[] listFiles = file.listFiles();
        for (File file2 : listFiles) {
            if (file2.isDirectory()) {
                getFileClass(file2, basePackage+"."+file2.getName());
            } else {
                classNames.add(basePackage + "." + file2.getName());
            }
        }
        return  classNames;
    }

}
